package lex.expression.tree;

import java.io.PrintStream;
import java.util.Arrays;
import java.util.Enumeration;

import javax.swing.tree.TreeNode;

import lex.expression.Element;
import lex.expression.Operand;
import lex.expression.Operator;



public class Node implements TreeNode
{
	private static final char INDENT_CHAR = ' ';
	private static final Node[] EMPTY_ARRAY = new Node[0];

	private Element element = null;
	private Node parent = null;
	private Node[] children = EMPTY_ARRAY;

	public static Node newChildNode( Element e )
	{
		return new Node( e );
	}

	public static Node newParentNode( Element e, Node ... children )
	{
		Node parent = new Node( e );
		parent.children = Arrays.copyOf( children, children.length );
		for( Node child : children )
			child.setParent( parent );
		return parent;
	}

	private Node( Element node )
	{
		this.element = node;
	}

	//==========================
	public Number getValue()
	{
		if( true == this.element.isOperand() )
			return ((Operand) element).getValue();
		else
		{
			return ((Operator) element).operate( children[0].getValue(),
				children[1].getValue() );
		}
	}

	//===========================
	public Enumeration children()
	{
		return new Enumeration(){
			private int index = 0;

			public boolean hasMoreElements()
			{
				return index < children.length;
			}

			public Object nextElement()
			{
				return children[index];
			}
		};
	}

	public boolean getAllowsChildren()
	{
		return this.element.isOperator();
	}

	public TreeNode getChildAt( int childIndex )
	{
		return this.children[childIndex];
	}

	public int getChildCount()
	{
		return this.children.length;
	}

	public int getIndex( TreeNode node )
	{
		if( node instanceof Node )
		{
			Node n = (Node) node;
			for( int i = 0; i < this.children.length; i++ )
				if( n == this.children[i] )
					return i;
		}
		return 0;
	}

	public void setParent( Node parent )
	{
		this.parent = parent;
	}

	public TreeNode getParent()
	{
		return parent;
	}

	public boolean isLeaf()
	{
		return element.isOperand();
	}

	public String toString()
	{
		if( null == this.element )
			return "null";
		if( true == element.isOperand() )
			return element.getImage();
		
		return element.getImage() + " [" + getValue().toString() + "]";
	}
	
	public void print( PrintStream out, int indent )
	{
		this.print0( out, 0, indent );
	}
	
	private void print0( PrintStream out, int indent, int step )
	{
		printIndent( out, indent );
		if( null == this.element )
			out.println( "null" );
		else if( true == this.element.isOperand() )
		{
			out.println( element.getImage() );
		}
		else
		{
			// this is an operator node
			out.println( element.getImage() );
			for( Node node : children )
				node.print0( out, indent + step, step );
		}
	}
	
	private void printIndent( PrintStream out, int n )
	{
		for( int i = 0; i < n; i++ )
			out.print( INDENT_CHAR );
	}
}
